package net.jeanhwea.ex1;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.StringTokenizer;

public class WebServer {
	private ServerSocket serverSocket;
	private String httproot;

	public WebServer(int port, String httproot) throws IOException {
		serverSocket = new ServerSocket(port);
		this.httproot = httproot;
	}

	public void run(){
		for(;;) {
			try {
				Socket clientSocket = serverSocket.accept();
				handleClientSession(clientSocket);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private String addSlash(String path) {
		path = path.trim();
		if (path.endsWith("" + File.separatorChar)){
			return path;
		}
		else{
			return path + File.separatorChar;
		}
	}

	private void handleClientSession(Socket socket) throws IOException{
		InputStream is = socket.getInputStream();
		InputStreamReader inputStreamReader = new InputStreamReader(is);
		BufferedReader in = new BufferedReader(inputStreamReader);

		OutputStream os = socket.getOutputStream();

		System.out.println("**New Request**");
		String first = in.readLine();
		System.out.println(first);

		String line;
		do {
			line = in.readLine();
			System.out.println(line);
		} while (line!=null && line.trim().length() > 0);

		StringTokenizer tok = new StringTokenizer(first);
		String method = (String) tok.nextElement();
		String path = (String) tok.nextElement();

		if (method.equalsIgnoreCase("GET"))
			sendFile(os, path);
		else
			error(os, 500, "Unsupported command");

		os.close();
		in.close();
		socket.close();
	}

	private String getContent(String path){
		path = path.toLowerCase();
		if (path.endsWith(".jpg") || path.endsWith(".jpeg"))
			return "image/jpeg";
		else if (path.endsWith(".gif"))
			return "image/gif";
		else if (path.endsWith(".png"))
			return "image/png";
		else
			return "text/html";
	}

	private void sendFile(OutputStream out, String path) throws IOException{
		StringTokenizer tok = new StringTokenizer(path, "/", true);
		String physicalPath = addSlash(httproot);

		while (tok.hasMoreElements()) {
			String e = (String) tok.nextElement();
			if (!e.trim().equalsIgnoreCase("/")) {
				physicalPath += e;
			} else
				physicalPath = addSlash(physicalPath);
		}

		if (physicalPath.endsWith(File.separator)){
			physicalPath = physicalPath + "index.html";
		}

		File file = new File(physicalPath);
		if (file.exists()){
			FileInputStream fis = new FileInputStream(file);
			byte buffer[] = new byte[(int) file.length()];
			fis.read(buffer);
			fis.close();
			this.transmit(out, 200, "OK", buffer, getContent(physicalPath));
		}
		else{
			this.error(out, 404, "File Not Found");
		}
	}

	private void transmit(OutputStream out, int code, String message, byte body[], String content) throws IOException {
		StringBuilder headers = new StringBuilder();
		headers.append("HTTP/1.1 ");
		headers.append(code);
		headers.append(' ');
		headers.append(message);
		headers.append("\n");
		headers.append("Content-Length: " + body.length + "\n");
		headers.append("Server: Heaton Research Example Server\n");
		headers.append("Connection: close\n");
		headers.append("Content-Type: " + content + "\n");
		headers.append("\n");
		out.write(headers.toString().getBytes());
		out.write(body);

	}

	private void error(OutputStream out, int code, String message) throws IOException  {
		StringBuilder body = new StringBuilder();
		body.append("<html><head><title>");
		body.append(code + ":" + message);
		body.append("</title></head><body><p>An error occurred.</p><h1>");
		body.append(code);
		body.append("</h1><p>");
		body.append(message);
		body.append("</p></body></html>");
		transmit(out, code, message, body.toString().getBytes(), "text/html");
	}

	public static void main(String args[]) {
		int port = 8080;
		String currentWorkDirectory = System.getProperty("user.dir");
		String physicalRoot = currentWorkDirectory + File.separator +"src\\test\\resource\\images";
		WebServer server = null;
		try {
			server = new WebServer(port, physicalRoot);
			server.run();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

